package cool.taomu.box.guice

import com.google.inject.AbstractModule
import com.google.inject.Guice
import com.google.inject.Scopes
import com.google.inject.TypeLiteral
import com.google.inject.name.Named
import com.google.inject.name.Names
import cool.taomu.box.asm.CreateClass
import cool.taomu.box.asm.entity.ClassEntity
import cool.taomu.box.guice.ann.Binder
import cool.taomu.box.guice.entity.a.Root
import cool.taomu.box.guice.util.TaomuNames
import java.util.ArrayList
import java.util.List
import javax.inject.Inject
import org.eclipse.xtend.lib.annotations.ToString
import org.junit.Test
import org.objectweb.asm.Type

import static org.junit.Assert.assertNull

interface IS {
	def void p();
}

@ToString
class Simpl implements IS {
	@Inject
	@Named("port")
	int port;

	new() {
		println("Hello new")
	}

	override p() {
		println("Hello Simpl")
	}

}

interface ISA {
	def void p();
}

class SAimpl implements ISA {
	@Inject
	IS s;

	override p() {
		s.p();
	}

}

interface ISC {
	def void p();
}

class SCimpl implements ISC {
	@Inject
	ISA s;

	override p() {
		println("Hello ")
		s.p();
	}

}

class A extends AbstractModule {
	override void configure() {
		var binder = binder();
		binder.bind(IS).to(Simpl);
	}
}

class B extends AbstractModule {
	override void configure() {
		var binder = binder();
		binder.bind(ISA).to(SAimpl);
	}
}

interface Ic<T>{}

class IcImpl implements Ic<Integer>{}
class ScImpl implements Ic<B>{}


class C extends AbstractModule {
	override void configure() {
		var binder = binder();

		binder.bind(int).annotatedWith(Names.named("port")).toInstance(Integer.parseInt("90"));
		binder.bind(new TypeLiteral<Ic<Integer>>() {}).annotatedWith(Names.named("port")).to(IcImpl);
		binder.bind(new TypeLiteral<Ic<B>>() {}).annotatedWith(Names.named("port")).to(ScImpl);
		binder.install(new A())
		binder.install(new B())
		binder.install(new D())
	}
}

@Binder(bind=int, value="100", named="port")
@Binder(bind=IS, to=Simpl)
@Binder(bind=ISA, to=SAimpl)
class D extends AbstractModule {
	override void configure() {
		var binder = binder();
		binder.bind(ISC).to(SCimpl);
	}
}

class NamesModule extends AbstractModule {
	override void configure() {
		var binder = binder();
		TaomuNames.bindYaml(binder, "test.yml")
	}
}

@Binder(bind=IS, to=Simpl)
@Binder(bind=int, value="100", named="port")
@Binder(bind=ISA, to=SAimpl)
class GuiceTest {

	var tgmodule = new TaomuGuiceModule();

	@Test
	def void installModule() {
		var g = Guice.createInjector(new C);
		var isa = g.getInstance(ISC)
		isa.p
		println(g.getInstance(IS))
	}

	@Test
	def void installModule2() {
		var module = tgmodule.build(GuiceTest);
		var g = Guice.createInjector(module);
		var isa = g.getInstance(ISA)
		isa.p
		println(g.getInstance(IS))
	}

	@Test
	def void installModule3() {
		var module = tgmodule.build(D);
		var g = Guice.createInjector(module);
		var isa = g.getInstance(ISC)
		isa.p
	}

	@Test
	def void taomuNames() {
		var g = Guice.createInjector(new NamesModule);
	}

	@Test
	def void taomuNames2() {
		var g = Guice.createInjector(new AbstractModule() {
			override void configure() {
				var binder = binder();
				TaomuNames.bindYaml(binder, "test2.yml", Root);
			}
		});
		println(g.getInstance(Root));
	}

	@Test
	def void bindTest2() {
		var a = Guice.createInjector(new AbstractModule() {
			override void configure() {
				var binder = binder();
				var classEntity = new ClassEntity("cool.taomu.box", "Aa");
				classEntity.superclass = Type.getType(Simpl).internalName;
				var cc = CreateClass.Class(classEntity);
				cc.constructor(Simpl.constructors)
				cc.end();
				binder.bind(Simpl).to(cc.loadClass("cool.taomu.box.Aa") as Class<Simpl>).in(Scopes.SINGLETON)
				println("aa");
			}
		})
		a.getInstance(Simpl).p();
		a.getInstance(Simpl).p();
	}

	@Test
	def void bindisNull() {
		var module = tgmodule.build(ISC);
		assertNull(module);
	}
	 
}
